using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using SuiHan.Commons.Daemon.Config;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace SuiHan.Commons.Daemon.Util {
    public static class DaemonUtils {
        private static readonly Dictionary<string, string> PathVariables = new();
        private const char Slash = '/';
        private const char BackSlash = '\\';
        private static readonly Regex SlashMulitReg = new("/+");
        private static readonly Regex BackSlashMulitReg = new("\\\\+");

        static DaemonUtils() {
            PathVariables.Add("%BASE%", ContextUtils.GetContextPath());
        }

        public static List<DaemonProcess> LoadDaemons() {
            string yaml = ContextUtils.GetContextResourcePath("daemon.yml");
            using StringReader stringReader = new(File.ReadAllText(yaml));

            IDeserializer deserializer = new DeserializerBuilder()
                .WithNamingConvention(CamelCaseNamingConvention.Instance)
                .Build();

            ApplicationConfig config = deserializer.Deserialize<ApplicationConfig>(stringReader);

            List<DaemonProcess> daemons = new();
            if ((config.WindowsServices?.Count ?? 0) > 0) {
                daemons.AddRange(config.WindowsServices.Where(it => it.Enabled).Select(it =>
                    new WindowsServiceDaemon(it.ServiceName) { Order = it.Order, Killable = it.Killable }));
            }

            if ((config.ProcessPaths?.Count ?? 0) > 0) {
                daemons.AddRange(config.ProcessPaths.Where(it => it.Enabled).Select(it =>
                    new ProcessPathDaemon(FormatPath(it.ExecutorPath), string.IsNullOrWhiteSpace(it.RunScript) ? null : FormatPath(it.RunScript),
                        it.Arguments) { Order = it.Order, Killable = it.Killable })
                );
            }

            daemons.Sort((a, b) => a.Order - b.Order);
            return daemons;
        }

        /// <summary>
        /// 格式化路径, 替换路径中的变量
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns></returns>
        private static string FormatPath(string path) {
            foreach (string variable in PathVariables.Keys.Where(variable => path.Contains(variable))) {
                path = path.Replace(variable, PathVariables[variable]);
            }

            return NormalizePath(path);
        }

        private static string NormalizePath(string path) {
            char sep = Path.DirectorySeparatorChar;
            if (sep == Slash) {
                path = path.Replace(BackSlash, sep);
                path = SlashMulitReg.Replace(path, sep.ToString());
            } else {
                path = path.Replace(Slash, sep);
                path = BackSlashMulitReg.Replace(path, sep.ToString());
            }

            return path;
        }
    }
}
